package htmlsoup

import (
	"bytes"
	"fmt"

	"code.google.com/awwwe-browser/data"
)

const (
	_                    = iota
	nodeTypeDocument int = iota
	nodeTypeDocType
	nodeTypeInstruction
	nodeTypeDirective
	nodeTypeCdata
	nodeTypeComment
	nodeTypeConditionalComment
	nodeTypeTag
	nodeTypeText
)

type SoupNode struct {
	nodeType                             int
	nodeCount, id                        int
	prefix, name                         string
	statics                              *nodeStatics
	nameSpaces                           map[string]string
	defaultNameSpace                     string
	value                                string
	attributes                           nodeAttributeArray
	validParentNames, inValidParentNames data.SliceString
	validChildrenNames                   data.SliceString
	forceClosedNames                     data.SliceString
	parent                               *SoupNode
	children                             SliceSoupNode
	isBlock, canBeBlock                  bool
	isHeadDecendent, isBodyDecendent     bool
	isValid                              bool
	isOutput                             bool
	useEndTag                            bool
	pauseBefore                          bool
	isClosed                             bool
	writeHandler                         func(*SoupNode, *bytes.Buffer)
	voiceHandler                         func(*SoupNode, *bytes.Buffer)
	attributesURLHandler                 func(*SoupNode)
	isVisible                            bool
}

func (this *SoupNode) DefaultTagPrefix() string {
	return this.statics.defaultNameSpace
}

func (this *SoupNode) ID() int {
	return this.id
}

func (this *SoupNode) Name() string {
	return this.name
}

func (this *SoupNode) Parent() *SoupNode {
	return this.parent
}

func (this *SoupNode) GetAttribute(name string) (string, string, string) {
	var attr *nodeAttribute
	attr = this.attributes.get(name)
	if attr != nil {
		return attr.prefix, attr.name, attr.value
	} else {
		return data.EmptyString, data.EmptyString, data.EmptyString
	}
}

func (this *SoupNode) HasAttribute(name string) bool {
	var attr *nodeAttribute
	attr = this.attributes.get(name)
	return attr != nil
}

func (this *SoupNode) ChildrenLen() int {
	return this.children.Len()
}

func (this *SoupNode) ChildrenProps() []string {
	var length int
	length = this.children.Len()
	var props []string = make([]string, 0, 5)
	var i int
	var ch *SoupNode
	for i = 0; i < length; i++ {
		ch = this.children.AtIndex(i)
		props = append(props, fmt.Sprintf("%s %d ( output:%v valid:%v visible:%v )", ch.name, ch.id, ch.isOutput, ch.isValid, ch.isVisible))
	}
	return props
}

func (this *SoupNode) IsValid() bool {
	return this.isValid && this.isOutput
}

func (this *SoupNode) SetVisibility(truefalse bool) {
	if this.isValid && this.isOutput {
		this.isVisible = truefalse
	} else {
		this.isVisible = false
	}
	children := this.children
	length := children.Len()
	for i := 0; i < length; i++ {
		child := children.AtIndex(i)
		child.SetVisibility(this.isVisible)
	}
}

func (this *SoupNode) IsVisible() bool {
	return this.isVisible
}

func (this *SoupNode) TextString() string {
	bfr := bytes.NewBuffer(data.EmptyBytes)
	this.voiceHandler(this, bfr)
	return bfr.String()
}

func (this *SoupNode) VoiceString() string {
	bfr := bytes.NewBuffer(data.EmptyBytes)
	this.voiceHandler(this, bfr)
	// now do the translations for voice
	return bfr.String()
}

func (this *SoupNode) VoiceBytes() []byte {
	bfr := bytes.NewBuffer(data.EmptyBytes)
	this.voiceHandler(this, bfr)
	return bfr.Bytes()
}

func (this *SoupNode) Children() []*SoupNode {
	length := this.children.Len()
	children := make([]*SoupNode, length, length)
	for i := 0; i < length; i++ {
		children[i] = this.children.AtIndex(i)
	}
	return children
}

func (this *SoupNode) AddVoiceAttribute(value string) {
	var att *nodeAttribute
	att = this.attributes.get(value)
	if att != nil {
		att.value = value
	} else {
		att = newNodeAttribute()
		att.name = data.AWWWEAttributeVoice
		att.value = value
		this.attributes.append(att)
	}
}
